/*
Copyright  2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
import {jsRsaSign, KEYUTIL, X509, KJUR, zulutodate} from 'jsrsasign';
import {Buffer} from 'buffer';
import {VerifyPrvKeyWithPass} from './cryptoHelper'
import {
    registerCopyright, registerUserCertificate, updateUserCertificate, destroyUser,
    getTransaction, getBlock, getAccountAddress, verifyHash, getChaininfo
} from './repchainRestHelper'
import moment from "moment/moment";


var repchain = {
    /**
     * 注册版权信息
     * @param hash 数字认证值
     * @param val  描述
     * @param password 密码
     * @param prv_key_pem 私钥
     * @param account_address 账户短地址
     * @param cb 回调函数
     */
    registerCopyright: function (hash, val, password, prv_key_pem, account_address, cb) {
        // Currently the encrypted pem prv key is derived from utils/encryptPrvKey.js
        // The password shold be a string: 12345678
        if (!VerifyPrvKeyWithPass(prv_key_pem, password)) {
            cb(new Error('输入密码错误'), null);
            return;
        }
        let prv_key_obj = KEYUTIL.getKey(prv_key_pem, password);
        let prv_key_pem_new = KEYUTIL.getPEM(prv_key_obj, 'PKCS8PRV');
        let register_txid;

        // K-V in repchain data state, key is the hash of the picture file, value is a string derived as following way
        let val_bf = Buffer.from(JSON.stringify(val));
        let val_bf_str = val_bf.toString('base64');

        registerCopyright(hash, val_bf_str, prv_key_pem_new, account_address, (err, result, local_txid) => {
            if (err) {
                cb(err, null);
            }
            else {
                console.log('register result: ', result);
                let result_json_obj = JSON.parse(result);
                if (result_json_obj.err) {
                    cb(new Error(result_json_obj.err), null);
                }
                else {
                    register_txid = result_json_obj.txid;
                    // To ensure local txid is same with response txid
                    if (register_txid != local_txid) {
                        cb(new Error('invalid transaction txid'), {});
                        return;
                    }
                    let certificate = {
                        certificate_number: register_txid,
                        owner_account_address: val.owner_account_address,
                        hash_algorithm: val.hash_algorithm,
                        picture_digital_identity: val.picture_digital_identity,
                        picture_desc: val.picture_desc,
                        block_timestamp: -1,
                        createdAt: new Date(),
                        status: false,

                    };
                    Meteor.call('certificate.insert', certificate, (err, result)=>{
                        if(err){
                            cb(err, null);
                        }else {
                            cb(null, register_txid);
                        }
                    });
                }
            }
        });
    },

    /**
     * Register normal user's certificate by Admin
     *@param certString certificate's string
     *@param desc certifacate's descripation
     *@param passwd user's private key's password
     *@param prv_key_pem user's private key pem
     *@param account_address user's account address
     *@return
     * */
    registerUserCertificate: function (certString, userInfo, passwd, prv_key_pem, account_address, cb) {
        let registerTxid;

        let description = Buffer.from(JSON.stringify(userInfo));
        let descBase64 = description.toString('base64');

        if (!VerifyPrvKeyWithPass(prv_key_pem, passwd)) {
            cb(new Error('输入密码错误'), null);
            return;
        }
        const cert = new X509();
        cert.readCertPEM(new Buffer(certString, 'base64').toString());
        let str_format = cert.getNotBefore().toString().length == 13?'YYMMDDhhmmssZ':'YYYYMMDDhhmmssZ';
        if(moment(cert.getNotAfter().toString(),str_format).diff(moment())<0){
            cb(new Error('证书已过期'), null);
            return;
        }
        let prv_key_obj = KEYUTIL.getKey(prv_key_pem, passwd);
        let prv_key_pem_new = KEYUTIL.getPEM(prv_key_obj, 'PKCS8PRV');


        registerUserCertificate(certString, descBase64, prv_key_pem_new, account_address, (err, result, localTxid) => {
            if (err)
                cb(err, null)
            else {
                let resultJsonObj = JSON.parse(result);
                if (resultJsonObj.err) {
                    cb(new Error(resultJsonObj.err), null);
                } else {
                    registerTxid = resultJsonObj.txid;
                    if (registerTxid != localTxid) {
                        cb(new Error('Invalid transaction txid'), null);
                        return;
                    }
                    try {

                        userInfo['status']=true;
                        userInfo['avatar']=faker.image.avatar();
                        userInfo['user_certificate_pem']= new Buffer(certString, 'base64').toString();
                        userInfo['account_address'] = resultJsonObj.result;
                        userInfo['createdAt'] = cert.getNotBefore();
                        console.log(resultJsonObj);
                        Meteor.call('registerUser.insert', userInfo, (err, result)=>{
                            if(err){
                                cb(err, null);
                            }else {
                                cb(null, registerTxid);
                            }
                        });
                    } catch (e) {
                        console.log(e);
                        cb(new Error("证书有错！"), null);
                    }
                }
            }
        });
    },

    /**
     * Update normal user's certificate by Admin
     *@param certString certificate's string
     *@param desc certifacate's descripation
     *@param passwd user's private key's password
     *@param prv_key_pem user's private key pem
     *@param account_address user's account address
     *@return
     * */
    updateUserCertificate: function (certString, userInfo, passwd, prv_key_pem, account_address, cb) {
        let updateTxid;

        const cert = new X509();
        cert.readCertPEM(new Buffer(certString, 'base64').toString());
        let str_format = cert.getNotBefore().toString().length == 13?'YYMMDDhhmmssZ':'YYYYMMDDhhmmssZ';
        if(moment(cert.getNotAfter().toString(),str_format).diff(moment())<0){
            cb(new Error('证书已过期'), null);
            return;
        }
        if (!VerifyPrvKeyWithPass(prv_key_pem, passwd)) {
            cb(new Error('输入密码错误'), null);
            return;
        }
        let prv_key_obj = KEYUTIL.getKey(prv_key_pem, passwd);
        let prv_key_pem_new = KEYUTIL.getPEM(prv_key_obj, 'PKCS8PRV');

        updateUserCertificate(certString, prv_key_pem_new, account_address, (err, result, localTxid) => {
            if (err) {
                cb(err, null);
                return;
            }
            else {
                let resultJsonObj = JSON.parse(result);
                if (resultJsonObj.err) {
                    cb(new Error(resultJsonObj.err), null);
                } else {
                    updateTxid = resultJsonObj.txid;
                    if (updateTxid != localTxid) {
                        cb(new Error('Invalid transaction txid'), null);
                    }
                    //console.log(value);
                    try {
                        userInfo['status']=true;
                        userInfo['avatar']=faker.image.avatar();
                        userInfo['user_certificate_pem']= new Buffer(certString, 'base64').toString();
                        userInfo['account_address'] = resultJsonObj.result;
                        userInfo['createdAt'] = cert.getNotBefore();
                        // userInfo['tx_id']= registerTxid;
                        console.log(userInfo)
                        console.log(resultJsonObj);
                        Meteor.call('registerUser.update', userInfo, (err, result)=>{
                            if(err){
                                cb(err, null);
                            }else {
                                cb(null, updateTxid);
                            }
                        });
                    } catch (e) {
                        console.log(e);
                        cb(new Error("证书有错！"), null);
                    }
                }
            }
        });
    },

    /**
     * destroy nomal user
     *@param account address string
     *@param passwd user's private key's password
     *@param prv_key_pem user's private key pem
     *@param account_address user's account address
     *@return
     * */
    destroyUser: function (user_account_addr, passwd, prv_key_pem, account_address, cb) {
        let destroyTxid;
        if (!VerifyPrvKeyWithPass(prv_key_pem, passwd)) {
            cb(new Error('输入密码错误'), null);
            return;
        }
        let prv_key_obj = KEYUTIL.getKey(prv_key_pem, passwd);
        let prv_key_pem_new = KEYUTIL.getPEM(prv_key_obj, 'PKCS8PRV');
        destroyUser(user_account_addr, prv_key_pem_new, account_address, (err, result, localTxid) => {
            if (err) {
                cb(err, null);
            } else {
                let resultJsonObj = JSON.parse(result);
                if (resultJsonObj.err) {
                    cb(new Error(resultJsonObj.err), null);
                } else {
                    destroyTxid = resultJsonObj.txid;
                    if (destroyTxid != localTxid)
                        cb(new Error('Invalid transaction txid'), null);
                    else {
                        Meteor.call('registerUser.destroy', user_account_addr, (err, result)=>{
                            if(err){
                                cb(err, null);
                            }else {
                                cb(null, destroyTxid);
                            }
                        });
                    }
                }
            }
        })
    },
    /**
     * 获取交易
     * @param txid 交易号
     * @param cb 回调函数
     */
    getTransaction: function (txid, cb) {
        let transaction;
        getTransaction(txid, (err, result) => {
            if (err!=null){
                cb(err, null);
            } else {
                let transaction_info = JSON.parse(result);
                if (transaction_info.result) {
                    let transaction__info_cut = {
                        txid: transaction_info.result.txid,
                        block_timestamp: moment(transaction_info.result.timestamp).unix(),
                        status: true,
                    }
                    transaction = transaction__info_cut;
                    cb(null, transaction)
                }
                else {
                    cb(new Error(txid + '交易不存在' + result), null);
                }
            }
        });
    },

    /**
     * 获取链信息
     * @param cb
     */
    getChaininfo:function(cb){
      getChaininfo((err, res)=>{
          if (err)
              cb(new Error(err), null);
          else {
              cb(null, JSON.parse(res));
          }
      })
    },

    /**
     * 获取块
     * @param id
     * @param cb
     */
    getblock: function (id, cb) {
        let block_info;
        getBlock(id, (err, result) => {
            if (err)
                cb(new Error(err), null);
            else {
                cb(null, JSON.parse(result));
            }
        });
    },

    /**
     *获取短地址
     * @param certificate 证书字符串 base64编码后
     */
    getAccountAddress: function (certificate, cb) {
        let accountAddr;
        getAccountAddress(certificate, (err, result) => {
            if (err)
                cb(err, null);
            else {
                let res = JSON.parse(result);
                cb(null, res.addr)
            }
            console.log(err)
            console.log(result);
        });
    },
    /**
     * 鉴别hash
     * @param hash
     * @param cb
     */
    verifyHash: function (hash, cb) {
        verifyHash(hash, (err, result) => {
            if (err) {
                cb(new Error(err), null)
            } else {
                cb(null, JSON.parse(result).result);
            }
            console.log(result)
        });
    }

}

export default repchain;